#include "server.h"

//获取当前时间
char* server_getCurTime()
{
    static char str[20] = {0};

    time_t curTm = time(NULL);
    struct tm *curTime = localtime(&curTm);

    int year,mon,mday,hour,min,sec;

    year = 1900 + curTime->tm_year;
    mon = 1 + curTime->tm_mon;
    mday = curTime->tm_mday;
    hour = curTime->tm_hour;
    min = curTime->tm_min;
    sec = curTime->tm_sec;

    sprintf(str,"%d/%02d/%02d %02d:%02d:%02d",year,mon,mday,hour,min,sec);
    
    return str;
}

//设置服务器地址复用
int server_setReuseAddr(int fd_socket)
{
    int opt = 1;

    return setsockopt(fd_socket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
}

//绑定服务器地址
int server_bindAddr(int fd_socket,int port)
{
    struct sockaddr_in addr_server;
    memset(&addr_server,0,sizeof(addr_server));

    addr_server.sin_family = AF_INET;
    addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_server.sin_port = htons(port);

    return bind(fd_socket,(struct sockaddr*)&addr_server,sizeof(addr_server));
}

//初始化tcp服务器
int server_socketInit()
{
    int fd_socket = socket(AF_INET,SOCK_STREAM,0);
    if(fd_socket == -1)
        return -1;

    if(server_setReuseAddr(fd_socket) == -1) {return -1;}
    if(server_bindAddr(fd_socket,SERVER_PORT) == -1) {return -1;}
    if(listen(fd_socket,10) == -1) {return -1;}

    return fd_socket;
}

//初始化连接服务器的客户端集合
void server_clientsInit(Client_t *clients)
{
    for(int i = 0; i < MAX_CLIENT; i++)
    {
        clients[i].fd = -1;
        memset(&clients[i].name,0,sizeof(clients[i].name));
    }
}

//获取客户端地址
int server_getClientAddr(int fd_client,struct sockaddr_in *addr_client)
{
    int len_addr = sizeof(struct sockaddr_in);

    return getpeername(fd_client,(struct sockaddr*)addr_client,&len_addr);
}

//运行服务器（epoll多路复用模型）
int server_run(int fd_socket,Client_t *clients)
{
    server_clientsInit(clients);

    int fd_epoll = epoll_create(MAX_CLIENT);
    if(fd_epoll == -1)
        return -1;

    struct epoll_event event,*arr_events;
    memset(&event,0,sizeof(struct epoll_event));
    arr_events = malloc(sizeof(struct epoll_event) * MAX_CLIENT);
    if(arr_events == NULL)
        return -1;

    event.events = EPOLLIN;
    event.data.fd = fd_socket;
    if(epoll_ctl(fd_epoll,EPOLL_CTL_ADD,fd_socket,&event) == -1)
        return -1;

    printfLog(EN_LOG_LEVEL_INFO,"%s Server running on PORT[%hu]\n",server_getCurTime(),SERVER_PORT);

    while(1)
    {
        static int timeout = 0;
        memset(arr_events,0,sizeof(struct epoll_event) * MAX_CLIENT);

        int n = epoll_wait(fd_epoll,arr_events,MAX_CLIENT,60000);
        if(n == -1)
            return -1;
        else if(n == 0)
        {
            timeout++;
            printfLog(EN_LOG_LEVEL_INFO,"%s No connections in %d minute\n",server_getCurTime(),timeout);
            continue;
        }

        timeout = 0;
        
        for(int i = 0; i < n; i++)
        {
            if(arr_events[i].events == EPOLLIN)
            {
                if(arr_events[i].data.fd == fd_socket)  //有新客户端连接服务器
                {
                    int fd_client = accept(fd_socket,NULL,NULL);
                    if(fd_client > 0)
                    {
                        struct sockaddr_in addr_client;
                        memset(&addr_client,0,sizeof(struct sockaddr_in));

                        char name_client[100] = {0};

                        if(server_getClientAddr(fd_client,&addr_client) == -1)
                            return -1;

                        printfLog(EN_LOG_LEVEL_INFO,"%s New client: [%s:%hu]\n",server_getCurTime(),inet_ntoa(addr_client.sin_addr),ntohs(addr_client.sin_port));

                        event.events = EPOLLIN;
                        event.data.fd = fd_client;
                        if(epoll_ctl(fd_epoll,EPOLL_CTL_ADD,fd_client,&event) == -1)
                            return -1;

                        for(int j = 0; j < MAX_CLIENT; j++)
                        {
                            if(clients[j].fd == -1)
                            {
                                clients[j].fd = fd_client;
                                strcpy(clients[j].name,name_client);
                                break;
                            }
                        }
                    }
                }
                else    //客户端有新动态
                {   
                    int fd_client = arr_events[i].data.fd;

                    struct sockaddr_in addr_client;
                    memset(&addr_client,0,sizeof(struct sockaddr_in));

                    if(server_getClientAddr(fd_client,&addr_client) == -1)
                        return -1;

                    int r_size = 1024 * 1024;
                    char *r_buf = malloc(r_size);
                    if(r_buf == NULL)
                        return -1;
                    
                    memset(r_buf,0,r_size);

                    int r_byte = recv(fd_client,r_buf,r_size,0);
                    if(r_byte == -1)
                        return -1;
                    else if(r_byte == 0)    //客户端断开连接
                    {
                        for(int j = 0; j < MAX_CLIENT; j++)
                        {
                            if(clients[j].fd == fd_client)
                            {
                                printfLog(EN_LOG_LEVEL_INFO,"%s Disconnected: [%s:%hu]\n",server_getCurTime(),inet_ntoa(addr_client.sin_addr),ntohs(addr_client.sin_port));
                                
                                clients[j].fd = -1;

                                memset(&clients[j].name,0,sizeof(clients[j].name));
                            }

                            break;
                        }

                        if(epoll_ctl(fd_epoll,EPOLL_CTL_DEL,fd_client,NULL) == -1)
                            return -1;

                        close(fd_client);
                    }
                    else    //客户端发送数据
                    {
                        printfLog(EN_LOG_LEVEL_INFO,"%s Receive data from [%s:%hu], data: %s\n",server_getCurTime(),inet_ntoa(addr_client.sin_addr),ntohs(addr_client.sin_port),r_buf);
                        
                        if(strstr(r_buf,"name: "))
                        {
                            for(int j = 0; j < MAX_CLIENT; j++)
                            {
                                if(clients[j].fd == fd_client)
                                {
                                    strcpy(clients[j].name,r_buf + strlen("name: "));

                                    printf("%s\n",clients[j].name);
                                }
                            }

                            continue;
                        }

                        int num_service = 1;
                        ST_IOTA_SERVICE_DATA_INFO services[num_service];

                        services[0].event_time = getEventTimeStamp();
                        services[0].service_id = "gec6818";
                        services[0].properties = r_buf;

                        if(IOTA_PropertiesReport(services, num_service) != 0)
                        {
                            printfLog(EN_LOG_LEVEL_ERROR,"%s Properties report error\n",server_getCurTime());
                        }
                    }

                    free(r_buf);
                    r_buf = NULL;
                }
            }
        }

    }
}